home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Add-Ons / After Dark / Peek-a-boo / Peek-a-Boo.c < prev    next >
Encoding:
Text File  |  1993-11-06  |  19.6 KB  |  638 lines  |  [TEXT/KAHL]

  1. // ver 1.1.3 changes - 6 Nov 93
  2. //        - added a check for running under System 7. I think the colorQD check
  3. //        kept a lot of the non-system7 users from crashing ... but since I use
  4. //         offscreen Gworlds which are (I think?) a System-7ism, I should check that.
  5. // ver 1.1.2 - was a resource change to the 'sysz'
  6. // ver 1.1.1 changes - 3 Oct 93
  7. //        - added Kramer sound to rsrc file
  8. //        - fixed RangedRdm() code and update the controlvalues to match as it is running
  9. // ver 1.1 changes     -    26 Sept 93
  10. //        - did the GetGWorldPixMap() in the slide_up and down routines
  11. //         I had forgotten to do that in a case
  12. //        - added a control checkbox for randomness and code
  13. //         - added a STR#/tVal to put a message underneath the faces menu (in the .rsrc)    
  14.  
  15. #include <QuickDraw.h>
  16. #include <Memory.h>
  17. #include <Resources.h>
  18.  
  19. #include <QDoffscreen.h>
  20.  
  21. #include "GraphicsModule_Types.h"
  22. #include "Sounds.h"
  23.  
  24. unsigned short RangedRdm( unsigned short min, unsigned short max );
  25.  
  26. // these are the functs that need defined ...
  27. OSErr DoInitialize(Handle *storage, RgnHandle blankRgn, GMParamBlockPtr params);
  28. OSErr DoClose(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  29. OSErr DoBlank(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  30. OSErr DoDrawFrame(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  31. OSErr DoSetUp(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  32.  
  33. // extra ones
  34. OSErr DoSelected(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  35. OSErr DoAboutBox(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  36. Boolean HasSystemSeven(void);
  37.  
  38. #define ONE_KNOCK_SND    256
  39. #define BASE_PICTID        127            // this is 1 less than the starting ID number (128)
  40.  
  41. #define NUMPICTS        26    
  42.  
  43. // states for the simple state machine ...
  44. #define STATE_DOWN            0
  45. #define STATE_GOING_UP        1
  46. #define STATE_UP            2
  47. #define STATE_LOOKING        3
  48. #define STATE_GOING_DOWN    4
  49. #define RANDOM_CHECK        5        // new
  50.  
  51.  
  52. // this is borrowed from the example code from Bouncing Ball ...
  53. /* some macros to simplify synchronizing to the vertical retrace. */
  54. #define SynchFlag(m) (params->monitors->monitorList[m].synchFlag)
  55. #define SynchVBL(m) synchFlag = &SynchFlag(m); *synchFlag = false; while(!*synchFlag);
  56.  
  57.  
  58.  
  59. typedef struct infostruct {
  60.     Boolean        soundAvailable;            // do we have sound?
  61.     Handle        oneKnockSound;            // one knock sound
  62.     GWorldPtr    gMyOffG;                // offscreen graphics world
  63.  
  64. // the face stuff
  65.     PicHandle    thePict;                // the face to slide up and down
  66.     PicHandle    eyes, eyesleft, eyesright;    // the eyes to slide left/right
  67.     Point        eyesPt;                    // where they eyes are supposed to be drawn
  68.     Handle        faceSound;                // a sound associated with a face
  69.     short        thePictNumber;            // the number of the picture we're using
  70.     Rect        theRect;                // rects for the sliding face
  71.     short        thePictWidth;            // time saving info on rect's width
  72.     short        thePictHeight;            // "    "        "        "       height
  73.  
  74.     SoundInfoHandle    soundInfo;            // AD sound info handle
  75.     Rect        theScreen;                // the monitor's screen rect
  76.     long        nextSoundTick;            // last tick when a the knocking sound was played
  77.     short        state;                    // the state we're in
  78. } infostruct, *infostructPtr, **infostructHandle;
  79.  
  80.  
  81.  
  82. // some prototypes ...
  83. void do_some_knocking(infostructPtr info, GMParamBlockPtr params);
  84. void slide_picture_up(infostructPtr info, GMParamBlockPtr params);
  85. void slide_picture_down(infostructPtr info, RgnHandle blankRgn, GMParamBlockPtr params);
  86. void slide_eyes_around(infostructPtr info, GMParamBlockPtr params);
  87.  
  88. //////////////////////////////////////////////////////////////////////////////////////
  89. // this is the first funct called by AD ... we need to allocate and initialize here
  90. OSErr
  91. DoInitialize(Handle *storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  92.  
  93. // ERROR MESSAGES ....
  94.     StringPtr         memoryMessage = (StringPtr)"\pmodule: Not enough memory!";
  95.     StringPtr         loadMessage = (StringPtr)"\pmodule: Could not load pict!";
  96.     StringPtr        offscreenMessage = (StringPtr)"\pmodule: Offscreen Bitmap failed!";
  97.     StringPtr        colorMessage = (StringPtr)"\pmodule: Must have color!";
  98.     StringPtr        menuMessage = (StringPtr)"\pmodule: Failed to get MENU!!";
  99.     StringPtr        systemMessage = (StringPtr)"\pmodule: Must have System 7!";
  100. // the variables ...
  101.     Handle             h;
  102.     Handle            tempHandle;
  103.     infostructPtr    mystorage;
  104.     GWorldPtr        currPort;        // something to save the port + device
  105.     GDHandle        currDev;
  106.     PixMapHandle    pixBase;
  107.     
  108.     // lets ensure we're running on a screen of some depth ... (yes? no? do we care?)
  109.     // no ... I don't care ...just go on and run and let it look wierd
  110.     // but we do need some color Quickdraw - I haven't put in the B&W offscreen 
  111.     // routines to do offscreen bitmaps 
  112.     if (!params->colorQDAvail) {
  113.         BlockMove(colorMessage, params->errorMessage, 1 + colorMessage[0]);
  114.         return ModuleError;                    // could not allocate space
  115.     }
  116.     // are offscreen gworlds a System 7 thing? or a colorqd thing?
  117.     // if it's system 7 ... I need to test!!
  118.     if (!HasSystemSeven()) {
  119.         BlockMove( systemMessage, params->errorMessage, 1 + systemMessage[0] );
  120.         return ModuleError;
  121.     }
  122.     
  123.     // allocate space here for my structure - whatever it may be
  124.     h = NewHandle( sizeof(infostruct) );    
  125.     
  126.     if (h == (Handle)nil) {
  127.         *storage = nil;
  128.         h = nil;
  129.         BlockMove(memoryMessage, params->errorMessage, 1 + memoryMessage[0]);
  130.         return ModuleError;                    // could not allocate space
  131.     }
  132.     
  133.     // Randomize...
  134.     params->qdGlobalsCopy->qdRandSeed = TickCount();
  135.     
  136.     // handle pointer to have
  137.     *storage = h;
  138.     
  139.     // lock down our storage so we can refer to it by pointer safely
  140.     MoveHHi(h);
  141.     HLock(h);    
  142.     
  143.     mystorage = (infostructPtr) *h;
  144.  
  145. ///////// load the sounds ...
  146.     // do we have sound support?
  147.     mystorage->soundAvailable = (params->systemConfig & SoundAvailable) != 0;
  148.  
  149.     if (mystorage->soundAvailable) {
  150.     
  151.         /* load the resources for our  sounds. */
  152.         mystorage->oneKnockSound = GetResource('snd ', ONE_KNOCK_SND);
  153.     
  154.         /* to use the sound functions in AD 2.0u we must pass in "params" */
  155.         mystorage->soundInfo = OpenSound(params);
  156.     }
  157.  
  158. // check randomness first ...
  159.     if (params->controlValues[1]) {        // We're random
  160.         MenuHandle theMenu;
  161.         short rCount, i;
  162.         
  163.         // how many menu items are there?
  164.         theMenu = (MenuHandle)GetResource('MENU', 1002);
  165.         if (theMenu == (MenuHandle)nil) {
  166.             DebugStr("\pBig problems!");
  167.         }
  168.         rCount = CountMItems( theMenu);                        // how many picts?
  169.         // pick one
  170.         params->controlValues[2] = mystorage->thePictNumber = RangedRdm(1, rCount);
  171.         // by setting the controlValues[2] parameter ... the menu changes in demo mode!
  172.         // Neat!
  173.             
  174.         ReleaseResource( (Handle)theMenu);
  175.     } else {
  176.         mystorage->thePictNumber = params->controlValues[2];
  177.     }
  178.         
  179.     mystorage->thePict = 
  180.             (PicHandle)GetResource('PICT', BASE_PICTID + mystorage->thePictNumber);
  181.  
  182.     if (mystorage->thePict == (PicHandle)nil) {
  183.         DoClose( h, (RgnHandle) nil, (GMParamBlockPtr) nil);
  184.         BlockMove(loadMessage, params->errorMessage, 1 + loadMessage[0]);
  185.         return ModuleError;                        // could not load pict
  186.     }
  187.         
  188.  
  189. ////// get it's sound ... if it's possible
  190.         mystorage->faceSound = GetResource('snd ', BASE_PICTID + mystorage->thePictNumber);
  191.  
  192. ////// get the eye pictures ... if it's possible
  193.     mystorage->eyes = (PicHandle)GetResource('PICT', 
  194.             ((BASE_PICTID + mystorage->thePictNumber) * 10) + 1);
  195.     mystorage->eyesleft = (PicHandle)GetResource('PICT', 
  196.             ((BASE_PICTID + mystorage->thePictNumber) * 10) + 2);
  197.     mystorage->eyesright = (PicHandle)GetResource('PICT', 
  198.             ((BASE_PICTID + mystorage->thePictNumber) * 10) + 3);
  199.  
  200. ////// get the eye Point resource ... if it's possible
  201.     if ( (tempHandle = GetResource('eyes', (BASE_PICTID + mystorage->thePictNumber))) != 
  202.             (Handle)nil) {
  203.         PointPtr p;
  204.         
  205.         p = (PointPtr)(*tempHandle);
  206.         mystorage->eyesPt = (*p);
  207.         ReleaseResource( tempHandle);
  208.     } else 
  209.         mystorage->eyesPt.h = mystorage->eyesPt.v = -1;
  210.     
  211. ///////
  212.     mystorage->theRect =  (*mystorage->thePict)->picFrame;
  213.     mystorage->thePictWidth = mystorage->theRect.right - mystorage->theRect.left;
  214.     mystorage->thePictHeight = mystorage->theRect.bottom - mystorage->theRect.top;
  215.     
  216.     
  217. //////////////////////////////////////////////////////////////////
  218. // lets setup the offscreen world
  219.     // save the current info
  220.     GetGWorld(&currPort,&currDev);
  221.     
  222.     // create the offscreen world (with the bounds of the picture)
  223.     if (NewGWorld(&(mystorage->gMyOffG), 0, &mystorage->theRect, nil, nil, 0) != noErr) {
  224.         DoClose( h, (RgnHandle) nil, (GMParamBlockPtr) nil);
  225.         BlockMove(offscreenMessage, params->errorMessage, 1 + offscreenMessage[0]);
  226.         return ModuleError;            
  227.     }
  228.     // keep it from moving
  229.     pixBase = GetGWorldPixMap( mystorage->gMyOffG );
  230.     LockPixels (pixBase);
  231.     
  232.     // point to the offscreen world
  233.     SetGWorld ((mystorage->gMyOffG), nil);
  234.     
  235.     // draw it
  236.     DrawPicture( mystorage->thePict, &mystorage->theRect );
  237.     // could release the resource now, you know.
  238.  
  239.     // done drawing, set the world back 
  240.     SetGWorld (currPort, currDev);
  241.     
  242.     // unlock those puppies
  243.     UnlockPixels (pixBase);
  244. //////////////////////////////////////////////////////////////////
  245.  
  246.     
  247.     mystorage->theScreen = params->monitors->monitorList[0].bounds;
  248.     mystorage->nextSoundTick = 0;
  249.     
  250.     mystorage->state = STATE_DOWN;
  251.  
  252.     HUnlock(h);
  253.     
  254.     return noErr;
  255. }
  256.  
  257. //////////////////////////////////////////////////////////////////////////////////////
  258. // the screen saver has been awakened! time to ditch the storage and wave goodbye
  259. OSErr 
  260. DoClose(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  261.     
  262.     infostructPtr    mystorage;
  263.     
  264.     HLock(storage);
  265.     
  266.     mystorage = (infostructPtr)*storage;
  267.     
  268.     if (mystorage->soundAvailable) {
  269.         CloseSound( mystorage->soundInfo, params->sndChannel);
  270.         
  271.         // knocking sound
  272.         if (mystorage->oneKnockSound != (Handle)nil)
  273.             ReleaseResource(mystorage->oneKnockSound);
  274.  
  275.         // the face's sound
  276.         if (mystorage->faceSound != (Handle)nil)
  277.             ReleaseResource(mystorage->faceSound);
  278.  
  279.     }
  280.     
  281.     
  282.     ReleaseResource( (Handle)mystorage->thePict);
  283.     // release the eye picts ... if they're there
  284.     if (mystorage->eyes != (PicHandle)nil)
  285.         ReleaseResource( (Handle)mystorage->eyes);
  286.     if (mystorage->eyesleft != (PicHandle)nil)
  287.         ReleaseResource( (Handle)mystorage->eyesleft);
  288.     if (mystorage->eyesright != (PicHandle)nil)
  289.         ReleaseResource( (Handle)mystorage->eyesright);
  290.         
  291.         
  292.     DisposeGWorld( mystorage->gMyOffG);
  293.     HUnlock(storage);
  294.     DisposHandle( storage);
  295.     return noErr;
  296. }
  297.  
  298.  
  299.  
  300. //////////////////////////////////////////////////////////////////////////////////////
  301. // make the screen go black
  302. OSErr
  303. DoBlank(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  304.  
  305.     FillRgn(blankRgn, params->qdGlobalsCopy->qdBlack);
  306.     return noErr;
  307.  
  308. }
  309.  
  310. //////////////////////////////////////////////////////////////////////////////////////
  311. // this is the workhorse routine. It does the continual screen work to make
  312. // this screen saver what it is.
  313. OSErr 
  314. DoDrawFrame(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  315.     infostructPtr    info;
  316.  
  317.  
  318.     HLock(storage);
  319.     info = (infostructPtr)*storage;
  320.  
  321.     // pay attention to the controls in demo mode ...
  322.     // - the menu (2) is different than the picture number ... someone must
  323.     // have changed the menu! -  so restart the module
  324.     if ( (params->controlValues[2]) != info->thePictNumber) {
  325.         DoClose(storage, blankRgn, params);    // ditch the storage
  326.         return RestartMe;                    // tell AD to reinit us
  327.     }
  328.  
  329.     // when sufficient time has passed ... the face should peep up
  330.     
  331.     switch (info->state) {
  332.     case RANDOM_CHECK:        // check for randomness ... 
  333.             // random is the current option  - so restart the module
  334.             if ( params->controlValues[1])  {    
  335.                 DoClose(storage, blankRgn, params);    // ditch the storage
  336.                 return RestartMe;                    // tell AD to reinit us
  337.             } else info->state = STATE_DOWN;        // not random?, then move on
  338.             break;
  339.     case STATE_DOWN:
  340.             do_some_knocking(info, params);
  341.             break;
  342.     case STATE_GOING_UP:
  343.             slide_picture_up(info, params);        
  344.             break;
  345.     case STATE_UP:
  346.             info->state = STATE_LOOKING;
  347.             break;
  348.     case STATE_LOOKING:
  349.             slide_eyes_around(info, params);
  350.             break;        
  351.     case STATE_GOING_DOWN:
  352.             slide_picture_down(info, blankRgn,  params);
  353.             break;
  354.     default:
  355.         info->state = STATE_DOWN; // this should not happen
  356.         break;
  357.     }
  358.     HUnlock(storage);
  359.     return noErr;
  360. }
  361. //////////////////////////////////////////////////////////////////////////////////////
  362. // this is called when they click on something in the control panel
  363. OSErr 
  364. DoSetUp(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  365.  
  366.     return noErr;
  367. }
  368.  
  369.  
  370. void
  371. slide_eyes_around(infostructPtr info, GMParamBlockPtr params)
  372. {
  373.  
  374.     // if there are eyes, eyesleft, eyesright, an eyes point *AND* a random chance
  375.     // then go ahead and play with the eyes
  376.     if (info->eyes != (PicHandle)nil &&
  377.             info->eyesleft != (PicHandle)nil &&
  378.                 info->eyesright != (PicHandle)nil &&
  379.                     info->eyesPt.h != -1 &&
  380.                     info->eyesPt.v != -1 &&
  381.                     (!(Random()%10)) ) {
  382.         Rect r;
  383.         short tempnum;
  384.         
  385.         r = (*info->eyes)->picFrame;
  386.         // what if the picFrame is not 0,0 origined? 
  387.  
  388.         // offset to where the pixmap's rect actually is on screen
  389.         OffsetRect( &r, info->theRect.left, info->theRect.top);
  390.         
  391.         // offset to where the eyes resource says it is
  392.         OffsetRect( &r, info->eyesPt.h, info->eyesPt.v); 
  393.         
  394.         // randomly choose which eye pict to display
  395.         tempnum = RangedRdm(0, 4);        // was 5 ... I like things a bit more abnormal
  396.         switch(tempnum) {
  397.             case 0:  DrawPicture( info->eyesleft, &r); break;
  398.             case 1:  DrawPicture( info->eyesright, &r); break;
  399.             // case 2, 3, 4, 5 ... all do normal eye things in the default
  400.             default: DrawPicture( info->eyes, &r); break;
  401.         }
  402.     }
  403.     
  404.     // make some noise, also?
  405.     if (!SoundBusy(info->soundInfo, params->sndChannel) && 
  406.             (info->faceSound != (Handle)nil)  &&
  407.              (!(Random()%100)) ) {
  408.             
  409.             PlaySound( info->soundInfo, params->sndChannel, info->faceSound);
  410.     }
  411.  
  412.  
  413.     // random chance to stop all this peering about and start sliding down
  414.     if (!(Random()%300) ) info->state = STATE_GOING_DOWN;
  415.     
  416. }
  417.  
  418.  
  419. void
  420. slide_picture_up(infostructPtr info, GMParamBlockPtr params)  {
  421.     Boolean *synchFlag;        /* pointer to speed up access to synch */
  422.     short DELTA;
  423.     GWorldPtr    worldPtr;        // temp ptr to help address stuff
  424.     GWorldPtr    currPort;        // something to save the port + device
  425.     GDHandle    currDev;
  426.             
  427.     // amount of pixels to slide is 1/5 the slider value ( {0..100} => {0..20} )
  428.     DELTA = 1 + params->controlValues[0] / 5;
  429.     
  430.     // if this is the first time, then setup theRect (where to draw on the screen)
  431.     if (info->theRect.top == 0 && info->theRect.left == 0) {
  432.         short leftrand;
  433.         // random horizontal offset on the screen so we don't always slide in 
  434.         // up from the same place
  435.         leftrand = RangedRdm( 0, (info->theScreen.right - info->theScreen.left)/2);
  436.         OffsetRect( &(info->theRect), 
  437.                 (info->theScreen).left + leftrand,  (info->theScreen).bottom);
  438.     }
  439.     
  440.     // slide them up a DELTA amount
  441.     OffsetRect( &(info->theRect), 0, -DELTA);
  442.     
  443.     // if they've bumped the top, or moved up so far that their bottom is above
  444.     // the screen's bottom, 
  445.     // or if they've moved so the eyes show and random chance
  446.     // it's time to stop moving up all together
  447.     
  448.     if ( (info->theRect.top <= info->theScreen.top) ||
  449.             (info->theRect.bottom <= info->theScreen.bottom) ||
  450.                 // if we're up past where the eyes show ... then randomly stop here
  451.                 (((info->theRect.top + info->eyesPt.v +
  452.                     ((*info->eyes)->picFrame.bottom - (*info->eyes)->picFrame.top ))
  453.                     < info->theScreen.bottom) && 
  454.                     (info->eyesPt.v != -1) &&
  455.                     !(Random()%20))
  456.             ) 
  457.     {
  458.         OffsetRect( &(info->theRect), 0, DELTA);    // move it back down a bit
  459.         info->state = STATE_UP;                        // we're all the way up now
  460.     } else {
  461.         PixMapHandle    pixBase, screenBase;
  462.  
  463.         worldPtr = info->gMyOffG;
  464.         GetGWorld(&currPort,&currDev);
  465.         
  466.         ForeColor (blackColor);
  467.         BackColor (whiteColor);
  468.         
  469.         pixBase = GetGWorldPixMap( worldPtr );
  470.         screenBase = GetGWorldPixMap( (GWorldPtr)currPort);
  471.         LockPixels ( pixBase );
  472.         LockPixels ( screenBase);
  473.         
  474.         // wait for vertical retrace
  475.         SynchVBL(0);
  476.         // blit it into place onscreen
  477.         CopyBits ( (BitMap *) (*pixBase),
  478.                     &((GrafPtr)currPort)->portBits, 
  479.                                                                     //&info->theRect, 
  480.                     &(worldPtr->portRect),
  481.                     &info->theRect, 
  482.                     srcCopy, nil);
  483.         UnlockPixels(pixBase);
  484.         UnlockPixels(screenBase);
  485.     }
  486. }
  487.  
  488. void
  489. slide_picture_down(infostructPtr info, RgnHandle blankRgn, GMParamBlockPtr params)  {
  490.     Boolean *synchFlag;        /* pointer to speed up access to synch */
  491.     Rect diffRect;
  492.     short DELTA;
  493.     GWorldPtr    worldPtr;        // temp ptr to help address stuff
  494.     GWorldPtr    currPort;        // something to save the port + device
  495.     GDHandle    currDev;
  496.     
  497.     DELTA = 1 + params->controlValues[0] / 5;
  498.     
  499.     OffsetRect( &(info->theRect), 0, DELTA);        // slide downward
  500.     
  501.     // if we've slid so far down that our top leaves the screen, we're done going down
  502.     if ( info->theRect.top >= info->theScreen.bottom) {
  503.         // new change ... time to do RANDOM check
  504.         //info->state = STATE_DOWN;    
  505.         info->state = RANDOM_CHECK;        // we've slid off the screen - random?
  506.         
  507.         // I'm anal retentive, so let's just make sure the screen if cleared...
  508.         FillRgn(blankRgn, params->qdGlobalsCopy->qdBlack);
  509.         // set the rect to 0,0 offset so we recognize the initial condition in slide_up
  510.         SetRect( &(info->theRect), 0, 0, info->thePictWidth, info->thePictHeight);
  511.     } else {
  512.         PixMapHandle    pixBase, screenBase;
  513.         
  514.         worldPtr = info->gMyOffG;
  515.         GetGWorld(&currPort,&currDev);
  516.     
  517.         ForeColor (blackColor);
  518.         BackColor (whiteColor);
  519.         
  520.         pixBase = GetGWorldPixMap( worldPtr);
  521.         screenBase = GetGWorldPixMap( (GWorldPtr)currPort);
  522.         LockPixels ( pixBase );
  523.         LockPixels ( screenBase);
  524.         
  525.         // wait for vertical retrace
  526.         SynchVBL(0);
  527.  
  528.         CopyBits ( (BitMap *) (*(worldPtr->portPixMap)),
  529.                     &((GrafPtr)currPort)->portBits, 
  530.                     &(worldPtr->portRect),
  531.                     &info->theRect, 
  532.                     srcCopy, nil);
  533.                     
  534.         UnlockPixels(pixBase);
  535.         UnlockPixels(screenBase);
  536.     }
  537. }
  538.  
  539.  
  540. // face is offscreen ... so it knocks on the glass a bit.
  541. void
  542. do_some_knocking(infostructPtr temp, GMParamBlockPtr params) {
  543.  
  544.     
  545.     
  546.     // if it is time to make noise again ...
  547.     if (TickCount() >= temp->nextSoundTick) {
  548.         // if it's not busy and we have sound and we have a sound resource, then do it
  549.         if (!SoundBusy(temp->soundInfo, params->sndChannel) && 
  550.                 (temp->oneKnockSound != (Handle)nil) )
  551.         {
  552.             short i, knocks;
  553.             long tempticks;
  554.             
  555.             // random number of knocks
  556.             knocks = RangedRdm(2, 6);
  557.             for (i=0; i<=knocks; i++) {
  558.                 PlaySound( temp->soundInfo, params->sndChannel, temp->oneKnockSound);
  559.                 // delay a random amount to give it some "human" like feel
  560.                 Delay(     RangedRdm(7, 12), &tempticks);
  561.                 
  562.             }
  563.             // lets not make sound until some amount later {5..15} seconds
  564.             temp->nextSoundTick = TickCount() + RangedRdm(300, 900);
  565.         }
  566.     } 
  567.     
  568.     // random chance to just stop all this knocking and start the show
  569.     if (!(Random()%200)) {
  570.         temp->nextSoundTick = 0;
  571.         temp->state = STATE_GOING_UP;
  572.     }
  573. }
  574.  
  575.  
  576.  
  577. OSErr DoSelected(RgnHandle blankRgn, short message, GMParamBlockPtr params)
  578. {
  579.     // I tried playing with params here and they don't seem instantiated,
  580.     // so don't play too much in this routine
  581.     return noErr;
  582. }
  583.  
  584.  
  585. // this is from the Think C reference code example ...
  586. unsigned short RangedRdm( unsigned short min, unsigned short max )
  587. /* assume that min is less than max */
  588. {
  589.     // uh ... not this isn't quite right - it's between 0 and 65535, not 65536
  590.     unsigned    qdRdm;    /* treat return value as 0-65536 */
  591.     long    range, t;
  592.     
  593.     // just to be safe, I'll put this here
  594.     if (min > max) DebugStr("\pMin greater then Max in RangedRdm");
  595.     
  596.     qdRdm = Random();
  597.     range = max - min;
  598.     // max - min gives us the the difference between max and min ... that is 
  599.     // not inclusive. It gives us { min <= range < max }
  600.     // so we never see that max number!!
  601.     range++;
  602.     t = ((long)qdRdm * range) / 65536;     /* now 0 <= t <= range */
  603.     return( t+min );
  604. }
  605.  
  606.  
  607.  
  608. OSErr DoAboutBox(RgnHandle blankRgn, short message, GMParamBlockPtr params)
  609. {
  610.     return noErr;
  611. }
  612.  
  613.  
  614.  
  615. #include <GestaltEqu.h>
  616. static Boolean
  617. HasSystemSeven( void )
  618.  
  619. {
  620.     long    gestResponse;
  621.     short    version;
  622.  
  623.     if (!Gestalt( gestaltVersion, &gestResponse )) {    
  624.     
  625.         // • Ensure that machine is running System 7 or higher. 
  626.     
  627.         Gestalt( gestaltSystemVersion, &gestResponse );
  628.         version = HiWord( gestResponse );
  629.         if (gestResponse >= 7) {            
  630.             return TRUE;
  631.         }
  632.  
  633.     }  
  634.     
  635.     return FALSE;
  636.  
  637. }
  638.